gusucode.com > 黑白棋 V1.0 试用网络版源代码C++源码程序 > 黑白棋 V1.0 试用网络版源代码/BWChess/03D407_庞长才_PROJECT作业/BWChess钻石版/BWChessDlg.cpp
// BWChessDlg.cpp : implementation file #include "stdafx.h" #include <math.h> #include <mmsystem.h>//播放声音的头文件 #include "BWChess.h" #include "SetupDlg.h" #include "AboutDlg.h" #include "Globalvar0.h" #include "HelperAPI.h" //定义了3个对话框函数 #include "BWChessDlg.h" #include "RecorDdlg.h" #include "BestDlg.h" #include <time.h> #include "SettingDlg.h" #include "Demo.h" #include "windows.h" #include "Message1.h" #include "ip1.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CBWChessDlg dialog BOOL PlaySounds(UINT IDSoundRes, WORD wFlag)//播放声音 { //PlaySound 是标准函数<win.h> if (g_bSoundOn) if (PlaySound(MAKEINTRESOURCE(IDSoundRes),//播放的声音资源 AfxGetInstanceHandle(),//指明实例 wFlag|SND_RESOURCE|SND_NODEFAULT))//标志位:不默认,使用实例包含的资源 return TRUE; return FALSE; } CBWChessDlg::CBWChessDlg(CWnd* pParent ): CDialog(IDD_BWCHESS_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);//载入图标 to m_hIcon ,不载入则使用默认图标 m_pMenu = new CMenu();//菜单 m_PaintNum=0; hAccelerator=::LoadAccelerators(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_ACC)); //载入加速键 g_nCanHintTimeB= 3; g_nCanHintTimeW= 3; g_nStrollSpeed= 2; //获得时间和速度 g_nStrollSpeed=abs(g_nStrollSpeed); g_nStrollSpeed%=3;//速度分为3种:低 中 高 g_nCanHintTimeB=abs(g_nCanHintTimeB); g_nCanHintTimeB%=31; if(g_nCanHintTimeB<3) g_nCanHintTimeB=3; g_nCanHintTimeW=abs(g_nCanHintTimeW); g_nCanHintTimeW%=31; if(g_nCanHintTimeW<3) g_nCanHintTimeW=3; //读注册表(关于英雄榜) g_nTime1 =AfxGetApp()->GetProfileInt(pSettings, _T("Time1"), 0); g_nTime2 =AfxGetApp()->GetProfileInt(pSettings, _T("Time2"), 0); g_nTime3 =AfxGetApp()->GetProfileInt(pSettings, _T("Time3"), 0); g_nMark1 =AfxGetApp()->GetProfileInt(pSettings, _T("Mark1"), 0); g_nMark2 =AfxGetApp()->GetProfileInt(pSettings, _T("Mark2"), 0); g_nMark3 =AfxGetApp()->GetProfileInt(pSettings, _T("Mark3"), 0); g_strName1 =AfxGetApp()->GetProfileString(pSettings, _T("Name1"), _T("Anonymous")); g_strName2 =AfxGetApp()->GetProfileString(pSettings, _T("Name2"), _T("Anonymous")); g_strName3 =AfxGetApp()->GetProfileString(pSettings, _T("Name3"), _T("Anonymous")); //写入注册表(关于英雄榜) CString str; str.LoadString (IDS_AUTHOR);//载入字符串 “庞长才 制作” AfxGetApp()->WriteProfileString(_T("Author"), _T("Shuker"), str); AfxGetApp()->WriteProfileInt(pSettings, _T("Time1"), g_nTime1); AfxGetApp()->WriteProfileInt(pSettings, _T("Time2"), g_nTime2); AfxGetApp()->WriteProfileInt(pSettings, _T("Time3"), g_nTime3); AfxGetApp()->WriteProfileInt(pSettings, _T("Mark1"), g_nMark1); AfxGetApp()->WriteProfileInt(pSettings, _T("Mark2"), g_nMark2); AfxGetApp()->WriteProfileInt(pSettings, _T("Mark3"), g_nMark3); AfxGetApp()->WriteProfileString(pSettings, _T("Name1"), g_strName1); AfxGetApp()->WriteProfileString(pSettings, _T("Name2"), g_strName2); AfxGetApp()->WriteProfileString(pSettings, _T("Name3"), g_strName3); } CBWChessDlg::~CBWChessDlg()//释放资源 { //以下为new对应的资源 delete m_pMenu; } void CBWChessDlg::InitParams() { for (int i=0; i<NUM;i++) for (int j=0; j<NUM; j++) kernel[i][j] = 0; //0 for none,1 for white,2 for black,棋盘的初态 kernel[3][3]=kernel[4][4]=2;//开局的 kernel[3][4]=kernel[4][3]=1;// 4颗子 m_CurPt.x = m_CurPt.y =-1;//放子的位置(初态) num_black=2;//黑白子 num_white=2;//的颗数 m_PassedTime=0;//黑棋流逝的时间 m_PassedTime0=0;//白棋流逝的时间 m_bGameOver = FALSE;//游戏是否已经结束 //m_byColor是本程序的核心变量!!!!!!!!!!!!!!! m_byColor = 0; //代表棋手的颜色,在使用之前代表前一个棋手的颜色, //使用完之后代表当前棋手的颜色,因此使用之前要将其取反 1:黑 0:白 m_Skip=0;//对方是否无子可下,即对方是否跳过不下 g_nStoneNum=0;//格子的个数 m_TimerOn=0;//时间是否在计数 m_HintOnce=0;//是否提示 m_PeekOnce=0;//是否查看可下棋的位置 m_IsGameStart=0;//游戏是否已经开始 m_ListInfo.ResetContent();//清空列表 m_HintTime0=0;//白棋点击的次数 m_HintTime1=0;//黑棋点击的次数 ListInfo.destroy();//stack 类,清空信息空栈 m_UndoPoint.Destroy();//undo类,清空悔棋信息空栈 } void CBWChessDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CBWChessDlg) //以下部分是将控件与变量联系起来 DDX_Control(pDX, IDC_TIME_CHINESE0, m_Time0);//白棋用时 DDX_Control(pDX, IDC_INFO, m_Info);//走棋信息 DDX_Control(pDX, IDC_LISTINFO, m_ListInfo);//走棋信息列表 DDX_Control(pDX, IDC_WNUM, m_Wnum);//白棋数目 DDX_Control(pDX, IDC_TIME_CHINESE, m_Time);//黑棋用时 DDX_Control(pDX, IDC_BNUM, m_Bnum);////黑棋数目 //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CBWChessDlg, CDialog)//消息映射函数 //{{AFX_MSG_MAP(CBWChessDlg) ON_WM_PAINT()//窗口内画图 ON_WM_LBUTTONDOWN() //鼠标左击 ON_COMMAND(IDM_NEW, OnNew) //菜 ON_COMMAND(IDM_EXIT, OnExit) //单 ON_COMMAND(IDM_ABOUT, OnAbout) //命令 ON_WM_SETCURSOR() ON_WM_QUERYDRAGICON() ON_WM_SYSCOMMAND() ON_WM_CONTEXTMENU()//弹出菜单 ON_WM_TIMER() ON_COMMAND(IDM_UNDO, OnUndo)//以下全为菜单命令 ON_COMMAND(IDM_BEST, OnBest) ON_COMMAND(IDM_HINT, OnHint) ON_COMMAND(IDM_CANPLACE, OnCanplace) ON_COMMAND(IDM_SETTING, OnSetting) ON_COMMAND(IDM_OPEN, OnOpen) ON_COMMAND(IDM_SAVE, OnSave) ON_COMMAND(IDM_SAVEINFO, OnSaveinfo) ON_COMMAND(IDM_DEMO, OnDemo) ON_COMMAND(ID_Onhost, OnHost) ON_COMMAND(ID_Onconnect, OnConnect) ON_COMMAND(ID_Unlink, OnUnlink) ON_COMMAND(IDM_REPLAY, OnReplay) //}}AFX_MSG_MAP ON_LBN_DBLCLK(IDC_LISTINFO , OnListDoubleClicked) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CBWChessDlg message handlers BOOL CBWChessDlg::OnInitDialog() { CDialog::OnInitDialog(); SetIcon(m_hIcon, TRUE); // Set big icon,m_hIcon是图标变量 SetIcon(m_hIcon, FALSE); // Set small icon CBitmap bitmap; bitmap.LoadBitmap(IDB_EMPTY); BITMAP bm; bitmap.GetBitmap(&bm); m_wStoneWidth=(unsigned short) bm.bmWidth; //bmWidth,bm.bmHeight m_wStoneHeight=(unsigned short)bm.bmHeight; CBitmap bitmap1; bitmap1.LoadBitmap(IDB_F1_2); bitmap1.GetBitmap(&bm); m_wFrameWidth=(unsigned short)bm.bmWidth; //bmWidth,bm.bmHeight m_wFrameHeight=(unsigned short)bm.bmHeight; //获取系统的相关信息 int cxScreen = ::GetSystemMetrics(SM_CXSCREEN); int cyScreen = ::GetSystemMetrics(SM_CYSCREEN); int cxDlgFrame = ::GetSystemMetrics(SM_CXDLGFRAME); int cyDlgFrame = ::GetSystemMetrics(SM_CYDLGFRAME); int cxCaption = ::GetSystemMetrics(SM_CYCAPTION); int cyMenu = ::GetSystemMetrics(SM_CYMENU);//系统菜单的宽度 int nWidth = m_wFrameHeight*2+ m_wFrameWidth*8 + 2*cxDlgFrame;//根据位图和系统参数 int nHeight = m_wFrameHeight*2+ m_wFrameWidth*8 + cxCaption + 2*cyDlgFrame + cyMenu;//确定界面的大下 MoveWindow((cxScreen-nWidth-230)/2, (cyScreen-nHeight)/2,nWidth+230, nHeight+2); //确定窗口的位置和大小,默认状态是响应重画消息 TimeCount.Create(this,nWidth+ 20, 40 ,0,4);//时间和棋子计数控件(自定义)的创建,4代表4位数,0无效 TimeCount0.Create(this,nWidth+20, 120 ,0,4); BCount.Create (this,nWidth+ 34, 230 ,0,2); WCount.Create (this,nWidth+ 34 ,310 ,0,2); // ShowNumber(1);static文本控件的位置和大小,以像素为单位,this的左上角为(0,0) m_Time.MoveWindow(nWidth+18 ,20 ,60,20); m_Time0.MoveWindow(nWidth+18 ,100 ,60,20); m_Bnum.MoveWindow(nWidth+18 ,210 ,60,20); m_Wnum.MoveWindow(nWidth+18 ,290 ,60,20); m_ListInfo.MoveWindow(nWidth+95,22,110,410);//列表 m_Info.MoveWindow(nWidth+95,2,110,20);//m_Infostatic文本 m_IsGameStart=1;//游戏是否开始 //设置系统菜单 CMenu* sysmenu=GetSystemMenu(FALSE); sysmenu->DeleteMenu(2,MF_BYPOSITION); sysmenu->DeleteMenu(0,MF_BYPOSITION); sysmenu->DeleteMenu(2,MF_BYPOSITION); CString str; str.LoadString(IDS_TITLE_CHINESE);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 m_pMenu->DestroyMenu(); m_pMenu->LoadMenu(IDR_MENU_CHINESE);//载入主界面菜单 SetMenu(m_pMenu); m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED);//提示无效 m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED);//悔棋无效 m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED);//查看可以下子的地方无效 m_pMenu->EnableMenuItem(IDM_SAVE,MF_GRAYED);//保存棋局无效 m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED);//导出走棋信息无效 m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED);//重温棋局无效 if(g_bTopMost)//最前面,不移动,不改变大小 SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); else//不是最前面 SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); m_wXNull = m_wFrameHeight+1;//9 //包括白线 m_wYNull = m_wFrameHeight+1;//10 m_Client.top = m_wYNull;//m_Client代表8*8棋盘 m_Client.left = m_wXNull; m_Client.bottom =m_wYNull + NUM * m_wStoneHeight; m_Client.right =m_wXNull + NUM * m_wStoneWidth; int i,j; for (i=0; i<NUM;++i) for (j=0; j<NUM; j++) kernel[i][j] = 0; //0代表无子 num_black=0; num_white=0; m_PassedTime=0; m_PassedTime0=0; m_TimerOn=0; m_HintOnce=0;//0 for have not hinted yet,1 for have hinted m_PeekOnce=0; m_HintTime0=0; m_HintTime1=0; m_bGameOver=TRUE; return TRUE; // return TRUE unless you set the focus to a control }//end OnInitDialog void CBWChessDlg::OnPaint() //游戏启动时作的一些准备工作 { CPaintDC dc(this); // device context for painting CDC * pdc=GetDC(); if (IsIconic())//如果窗口已最小化,画图标(意义不大) { SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); int cxIcon = GetSystemMetrics(SM_CXICON);//获取图标的大小,像素为单位 int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect);//获得画图区,并画图于窗口中间 int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon);//m_hIcon 代表图标 } else//normal 大小 { ShowNumber(1);//显示计数器控件 DrawFrame(&dc);//显示棋盘边框 BYTE t; if(!m_IsGameStart)//没开始 { for (int i=0; i<NUM; ++i) for (int j=0; j<NUM; ++j) { t=(unsigned char)(kernel[i][j]-1); if (kernel[i][j])//0 for none, 1 for white,2 for black, PutStone(t, CPoint(j,i), &dc);//画棋盘 PutStone:画棋子 } if(m_CurPt.x >=0)//m_CurPt.x/y 取0——7 { int nX = m_CurPt.x*m_wStoneWidth + m_wXNull;//计算棋子的位置(nx,ny) int nY = m_CurPt.y*m_wStoneHeight + m_wYNull; int byColor= kernel[m_CurPt.y][m_CurPt.x]-1;//棋子的颜色 :白 黑 if (byColor == 0)//白 DrawBitmap(pdc,nX,nY,IDB_CURWHITE, SRCCOPY); else if (byColor == 1)//黑 DrawBitmap(pdc,nX,nY,IDB_CURBLACK, SRCCOPY); } //此处画棋子 }//end if(!m_IsGameStart) if(m_HintOnce)//0 for have not hinted yet,1 for have hinted :m_HintOnce代表是否提示 { COLORREF crColor = m_byColor ? RGB(255,255,255) : RGB(0,0,0);//确定颜色 CPen pen(PS_SOLID, 2, crColor); CPen *pOldPen = dc.SelectObject(&pen); //画 提示符 “X” dc.MoveTo(x1, y1); dc.LineTo(x2, y1); dc.LineTo(x2, y2); dc.LineTo(x1, y2); dc.LineTo(x1, y1); dc.LineTo(x2, y2); dc.MoveTo(x2, y1); dc.LineTo(x1, y2);//x1 y1 x2 y2 的初值????? dc.SelectObject(pOldPen); } if(m_PeekOnce)//代表是否查看可下的位置,画可下的位置 { int px,py; int xx1,yy1; int length,hy; if(m_byColor)//黑 length=wsp.isempty(); else//白 length=bsp.isempty(); if(length) return; do { if(m_byColor)//从栈里取可放子的格子 length=wsp.GetNextPos(&py,&px,&hy);//有效格子的个数 else length=bsp.GetNextPos(&py,&px,&hy); xx1 = px*m_wStoneWidth + m_wXNull;//-4 + m_cxGrid / 2; yy1 = py*m_wStoneHeight + m_wYNull;//-4 + m_cyGrid / 2; if(m_byColor)//显示可放子的格子(显示一个标志性的位图) DrawBitmap(pdc,xx1,yy1,IDB_CANPLACE2, SRCCOPY); else DrawBitmap(pdc,xx1,yy1,IDB_CANPLACE1, SRCCOPY); }while(length); if(m_byColor) wsp.CopyBackIndex (); else bsp.CopyBackIndex (); } Mutex1.Lock();//互斥,在“Globalvar0.h”里定义的变量 if(g_nIsDemo && g_nMutex) { g_nMutex=0; m_Mutex.Unlock();//互斥,在“Globalvar0.h”里定义的变量 } Mutex1.Unlock(); } ReleaseDC(pdc); }//end paint HCURSOR CBWChessDlg::OnQueryDragIcon()//返回图标 { return (HCURSOR) m_hIcon;//返回图标 } void CBWChessDlg::OnLButtonDown(UINT nFlag, CPoint point)//左击 { if(!ready)// P 操作!!!!!!!! return; CPoint pt; if(!IsInPanel(point) || m_bGameOver || g_nIsDemo) return;//无效 返回 //此处为非网络模式 if (g_nRunMode != MODE_NETWORK&&PointToStonePos(point, pt)) { int nX = pt.x; int nY = pt.y; if (kernel[nY][nX]==0) //此处无子 { if (g_nRunMode == MODE_WITH_COMPUTER)//模式是与计算机对弈 { if ((g_bUserBlack && !m_byColor) || (!g_bUserBlack && m_byColor)) //数据正确 { // User m_byColor = !m_byColor; // 0-Black 1-White//设置当前棋手的颜色,因为初值为黑色棋手, //但是m_byColor==0,代表白色,所以要先设成黑色 //undo duplicate();//保存副本 //end undo if(BtoW(nY,nX,m_byColor+1))//将棋盘上被夹住的子变色 { m_HintOnce=0; m_PeekOnce=0; m_CurPt=pt; AddStringToList(nY,nX,m_byColor);//将信息加入列表框 InvalidateRect(m_Client, FALSE);//刷新窗口 UpdateWindow();//显示窗口 PlaySounds(IDSOUND_PUTSTONE); Ring(IsEnd(!m_byColor+1));//根据棋盘的状态处理善后工作 // -1 for both //棋盘的状态: // 0 for the int have no position //1 for the int have one position ,no use now //return 2 for have more than one //函数原型:int CBWChessDlg::IsEnd(int whogo); //whogo :1代表黑色,2代表白色 // Computer if (!m_bGameOver && !m_Skip) { do { m_byColor = !m_byColor; // 1-Black 0-White int ptBest_x,ptBest_y; //undo duplicate();//保存副本 //end undo Place(&ptBest_x,&ptBest_y,m_byColor+1);//计算机寻找最佳位置 //函数原型:void Place(int *x, int *y,int color,int nSkill) //color: 1 白 2 黑 BtoW(ptBest_x,ptBest_y,m_byColor+1);//将棋盘上被夹住的子变色 CPoint pt; pt.x = ptBest_y*m_wStoneWidth + m_wXNull+m_wStoneWidth/2; pt.y = ptBest_x*m_wStoneHeight + m_wYNull+m_wStoneWidth/2; m_CurPt.x=ptBest_y; m_CurPt.y=ptBest_x; ClientToScreen(&pt); MoveCursor(pt.x, pt.y);//移动光标,此时m_byColor代表的是当前棋手的颜色 InvalidateRect(m_Client, FALSE); UpdateWindow();//更新棋盘 AddStringToList(ptBest_x,ptBest_y,m_byColor);//将信息加入列表框 PlaySounds(IDSOUND_PUTSTONE); Ring(IsEnd(!m_byColor+1));//作善后处理,包括“游戏结束或对手无子可走” }while(m_Skip);//m_Skip==1表示对手无子可走,由计算机继续走 } if(!m_bGameOver && g_bPeepOften) OnCanplace();//继续搜索 } else//没有夹住任何棋子,撤消已有的操作 { int temp[NUM*NUM]; m_UndoPoint.pop(temp); m_byColor=!m_byColor; PlaySounds(IDSOUND_ERROR); } } // end if ((g_bUserBlack && !m_byColor) ||(!g_bUserBlack && m_byColor)) }// end 模式是与计算机对弈 else if (g_nRunMode == MODE_2PLAYER)// 人对人!! // Users { m_byColor = !m_byColor; // 1-Black 0-White,由当前棋手的ID取得当前棋手的颜色, //颜色与ID正好相反,故取反 duplicate(); if(BtoW(nY,nX,m_byColor+1))//有棋子可变色 { m_HintOnce=0;//不提示 m_PeekOnce=0;//不查看 m_CurPt=pt; AddStringToList(nY,nX,m_byColor); InvalidateRect(m_Client,FALSE); UpdateWindow(); PlaySounds(IDSOUND_PUTSTONE); Ring(IsEnd(!m_byColor+1)); if(!m_bGameOver && g_bPeepOften) OnCanplace(); } else//没有夹住任何棋子,撤消已有的操作 { int temp[NUM*NUM]; m_UndoPoint.pop(temp); m_byColor=!m_byColor; PlaySounds(IDSOUND_ERROR); } }//end 人对人!! else ;//此情况非法!! }//end 此处无子 else//有子 PlaySounds(IDSOUND_ERROR); }//end “if (PointToStonePos(point, pt))” else if (!PointToStonePos(point, pt))//无子 PlaySounds(IDSOUND_ERROR); //此处为非网络模式 ////模式是网络模式 if(Sever==0||Sever==1)//已连网 if (g_nRunMode == MODE_NETWORK&&PointToStonePos(point, pt)) { int nX = pt.x; int nY = pt.y; if (kernel[nY][nX]==0) //此处无子 { if ((g_bUserBlack && !m_byColor) || (!g_bUserBlack && m_byColor)) //数据正确 { m_byColor = !m_byColor; // 0-Black 1-White//设置当前棋手的颜色,因为初值为黑色棋手, //但是m_byColor==0,代表白色,所以要先设成黑色 duplicate();//保存副本 if(BtoW(nY,nX,m_byColor+1))//将棋盘上被夹住的子变色 { m_Mutex.Lock(); m_HintOnce=0; m_PeekOnce=0; m_CurPt=pt; AddStringToList(nY,nX,m_byColor);//将信息加入列表框 InvalidateRect(m_Client, FALSE);//刷新窗口 UpdateWindow();//显示窗口 PlaySounds(IDSOUND_PUTSTONE); Ring(IsEnd(!m_byColor+1));//根据棋盘的状态处理善后工作 //正确调用 if(!m_bGameOver && g_bPeepOften)//m_Skip为1,显示自己的位置,否则显示对方的位置 OnCanplace(); if(m_Skip==1) ready=true; else ready=false; if(m_bGameOver) ready=false; if(m_bGameOver) Senddata(nX,nY,CMD_OVER);//发数据给对方, V 操作!!!!! if(m_Skip==1) Senddata(nX,nY,CMD_SKIP);//发数据给对方, V 操作!!!!! Senddata(nX,nY,CMD_CLICK);//发数据给对方, V 操作!!!!! m_Mutex.Unlock(); }//end if(BtoW(nY,nX,m_byColor+1)) else//没有夹住任何棋子,撤消已有的操作 { int temp[NUM*NUM]; m_UndoPoint.pop(temp); m_byColor=!m_byColor; PlaySounds(IDSOUND_ERROR); } } // end if ((g_bUserBlack && !m_byColor) ||(!g_bUserBlack && m_byColor)) } }//此处为网络模式 else if (!PointToStonePos(point, pt))//无子 PlaySounds(IDSOUND_ERROR);//发出错误声音 //以上为网络模式 //将其它工作传给基类处理 CDialog::OnLButtonDown(nFlag, point); } //end OnLButtonDown int CBWChessDlg::Distance(const CPoint &pt1, const CPoint &pt2)//计算两点间的距离 { return (int)sqrt((double)(pt1.x-pt2.x)*(pt1.x-pt2.x) + (double)(pt1.y-pt2.y)*(pt1.y-pt2.y)); } BOOL CBWChessDlg::IsStonePoint(CPoint& ptStone)//检查是否在棋格内 { if (ptStone.x<0 || ptStone.x>=NUM || ptStone.y<0 || ptStone.y>=NUM) {//不合法,矫正到最边缘 if (ptStone.x<0) ptStone.x = 0; else if (ptStone.x>=NUM) ptStone.x = NUM-1; if (ptStone.y<0) ptStone.y = 0; else if (ptStone.y>=NUM) ptStone.y = NUM-1; return FALSE; } return TRUE; } BOOL CBWChessDlg::PointToStonePos(const CPoint &pt, CPoint& ptStone)//将客户区坐标转化为棋盘坐标 { int nPosX = (pt.x - m_wXNull-m_wStoneWidth/2)/m_wStoneWidth;//粗略计算棋盘坐标,有误差 int nPosY = (pt.y - m_wYNull-m_wStoneWidth/2)/m_wStoneHeight; CPoint pt0(nPosX * m_wStoneWidth + m_wXNull+m_wStoneWidth/2, nPosY*m_wStoneHeight+m_wYNull+m_wStoneWidth/2); CPoint pt1((nPosX+1)*m_wStoneWidth+m_wXNull+m_wStoneWidth/2, nPosY*m_wStoneHeight+m_wYNull+m_wStoneWidth/2); CPoint pt2((nPosX+1)*m_wStoneWidth+m_wXNull+m_wStoneWidth/2, (nPosY+1)*m_wStoneHeight+m_wYNull+m_wStoneWidth/2); CPoint pt3(nPosX*m_wStoneWidth+m_wXNull+m_wStoneWidth/2, (nPosY+1)*m_wStoneHeight+m_wYNull+m_wStoneWidth/2); //四个参照点,选择误差最小的一点 int nDis0 = Distance(pt, pt0); int nDis1 = Distance(pt, pt1); int nDis2 = Distance(pt, pt2); int nDis3 = Distance(pt, pt3); int nLimit = m_wStoneWidth/2-4; if (nDis0 <= nLimit) ptStone = CPoint(nPosX, nPosY); else if (nDis1 <= nLimit) ptStone = CPoint(nPosX+1, nPosY); else if (nDis2 <= nLimit) ptStone = CPoint(nPosX+1, nPosY+1); else if (nDis3 <= nLimit) ptStone = CPoint(nPosX, nPosY+1); else//不在棋盘内 { int nMin1 = min(nDis0, nDis1); int nMin2 = min(nDis2, nDis3); int nMin = min(nMin1, nMin2); if (nMin == nDis0) ptStone = CPoint(nPosX, nPosY); else if (nMin == nDis1) ptStone = CPoint(nPosX+1, nPosY); else if (nMin == nDis2) ptStone = CPoint(nPosX+1, nPosY+1); else if (nMin == nDis3) ptStone = CPoint(nPosX, nPosY+1); IsStonePoint(ptStone);//矫正到棋盘上 return FALSE; } return IsStonePoint(ptStone); } void CBWChessDlg::Ring(int m_nType)//处理走完一步棋之后的善后处理 { Calcu_BW(); ShowNumber(); m_Skip=0;//only when m_nType==0,then m_Skip==1; //other m_Skip==0; switch(m_nType) { case -1://游戏结束 { int win=0; int addp=0; m_bGameOver = TRUE; if(m_TimerOn) { KillTimer(PASSEDTIME); m_TimerOn=0; } m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_REPLAY,MF_ENABLED); CString str1,str2, str3,strPrompt; TCHAR str[64]; str2.LoadString(IDS_TITLE_CHINESE);//“黑白棋” if(g_nRunMode == MODE_2PLAYER)//两人对战 { if(num_white<num_black) { addp=2; str1.LoadString(IDS_BLACKWIN_CHINESE);//“本局黑棋胜。” } else if(num_white>num_black) { addp=1; str1.LoadString(IDS_WHITEWIN_CHINESE);//“本局白棋胜。” } else { addp=3; str1.LoadString(IDS_TIE_CHINESE);//“本局平手。\n我们的水平不分上下!” } str3.LoadString(IDS_END_CHINESE);//“黑棋%d子,白棋%d子。\n” wsprintf(str, str3.GetBuffer(256), num_black,num_white); strPrompt = str; strPrompt += str1; } else//人机对战 { g_nStoneNum=abs(num_black-num_white); g_nBestMark=abs((num_white+num_black)*(num_white-num_black));//计算得分,公式是|A*A-B*B| if(!(num_black && num_white))//吃光了,再加800 g_nBestMark+=800; if(num_white>num_black)//白 胜 addp=1; if(num_white<num_black)//黑 胜 addp=2; if(num_white==num_black)//平局 { str1.LoadString(IDS_TIE_CHINESE);//“本局平手。\n我们的水平不分上下!” win=1; addp=3; } else if((g_bUserBlack && (num_white>num_black)) || ((!g_bUserBlack) && (num_white<num_black))) {//人是输家 if(!num_white || !num_black) str1.LoadString(IDS_COMPUTERWIN0_CHINESE);//“你的棋子被我全吃掉了!\n再去研究一下规则吧!” else if(g_nStoneNum>=40)//“你真是太差了,我胜了%d你手。\n回去多练几年吧!” str1.LoadString(IDS_COMPUTERWIN1_CHINESE); else//“我赢了。胜你%d手。\n你还不行,好好锻炼一下吧!” str1.LoadString(IDS_COMPUTERWIN2_CHINESE); } else if((g_bUserBlack && (num_white<num_black)) || ((!g_bUserBlack) && (num_white>num_black))) {//人是赢家 win=1; if(!num_white || !num_black)//“你好厉害,居然把我的棋全吃掉了!\n佩服佩服!” str1.LoadString(IDS_USERWIN0_CHINESE); else if(g_nStoneNum<=6)//“恭喜,你获胜了。胜了我%d手。\n愿意再较量一盘吗?” str1.LoadString(IDS_USERWIN2_CHINESE); else//“你才胜了我%d手,我不服!\n有种再下一盘!” str1.LoadString(IDS_USERWIN1_CHINESE); } if(num_white!=num_black) { if(num_white && num_black) { wsprintf(str, str1.GetBuffer(256), g_nStoneNum); strPrompt=str; } else strPrompt=str1; } else strPrompt=str1;//载入胜负信息 }// end人机对战 AddStringToList(0,0,0,addp);//载入胜负信息与列表 if(g_nRunMode == MODE_2PLAYER)//人人对战 PlaySounds(IDSOUND_USERWIN); else//人机对战 PlaySounds((win==0) ? IDSOUND_COMPUTERWIN : IDSOUND_USERWIN ); MsgBox(strPrompt,str2);//弹出胜负的对话框 BOOL bWinner = FALSE; if (g_nBestMark>g_nMark1) bWinner = TRUE;//打破了记录 if (g_nRunMode == MODE_WITH_COMPUTER && bWinner && (win==1))//存储记录 { CRecordDlg recordDlg; // int result= recordDlg.DoModal(); // if(result==IDOK) // OnBest(); } } break; case 0://表示某一方不能下,m_Skip==1;由另外一方(m_byColor方:1黑,0白)继续下 { CString str3,str2; if(g_nRunMode == MODE_WITH_COMPUTER)//人机对战 { if((g_bUserBlack && !m_byColor) || (!g_bUserBlack && m_byColor)) //m_byColor代表应下棋的颜色,当棋手的颜色与m_byColor不匹配时表示当前棋手不能下 str3.LoadString(IDS_USER_NOPLACE_CHINESE);//“你无处可走,只能让我走.” else if((g_bUserBlack && m_byColor) || (!g_bUserBlack && !m_byColor)) str3.LoadString(IDS_COMPUTER_NOPLACE_CHINESE);//“我没法走了,只能让你走了.” } if(g_nRunMode == MODE_2PLAYER)//人人 { if(!m_byColor)//该白色下,则黑色不能下 str3.LoadString(IDS_BLACK_NOPLACE_CHINESE);//“黑棋无处可走。” else//该黑色色下 str3.LoadString(IDS_WHITE_NOPLACE_CHINESE);//“白棋无处可走” } str2.LoadString(IDS_TITLE_CHINESE); MsgBox(str3,str2); //important type m_Skip=1; // m_byColor=!m_byColor;//由于:OnLButtonDown(UINT nFlag, CPoint point)每次在走棋之前,都会反色, //因此在此处先反色,确保走棋的正确 } break; } } void CBWChessDlg::OnNew()//响应 “新棋盘” 菜单命令 { int HaveKilled=0; if(m_TimerOn)//停止计时 { HaveKilled=1; KillTimer(PASSEDTIME); m_TimerOn=0; } //备份数据 int a=m_bGameOver; int b=g_nRunMode; CSetupDlg setupDlg;//创建设置对话框 if (setupDlg.DoModal()==IDCANCEL)//取消了 { if(HaveKilled)//恢复计时 { SetTimer(PASSEDTIME,1000,NULL); m_TimerOn=1; } return; } if(!a&&b==MODE_NETWORK)//当前游戏没有结束 { Senddata(0,0,CMD_RESIGN); m_bGameOver=TRUE; } CString str; //对相关参数进行初始化 if(g_nRunMode==MODE_WITH_COMPUTER)//人机0 { if (g_nRunMode==MODE_WITH_COMPUTER && !g_bUserBlack) { str.LoadString(IDS_SINGLE_COMPUTER_CHINESE);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 } else { str.LoadString(IDS_SINGLE_USER_CHINESE);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 } ready=1; } if(g_nRunMode==MODE_2PLAYER)//人人1 { if(g_nIsNoTimeLimit) { str.LoadString(IDS_DOUBLE_NOLIMIT_CHINESE);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 } else { str.LoadString(IDS_DOUBLE_LIMIT_CHINESE);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 } ready=1; } if(g_nRunMode==MODE_NETWORK)//网络2 { if(Sever==2)//非网络模式 { str.LoadString(IDS_NONETWORK);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 AfxMessageBox("请先连上网络"); return; } else if(Sever==1) { str.LoadString(IDS_SERVER);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 g_bUserBlack = TRUE;//先手 g_nSkill = 1;//棋力 g_nTimeLimit=60;//允许等待的最大时间 from 60 to 9000,单位秒 g_nIsNoTimeLimit=1;//限时 ready=1; } else if(Sever==0) { str.LoadString(IDS_CLIENT);//IDS_TITLE_CHINESE:“黑白棋” SetWindowText(str);//设置标题 g_bUserBlack = FALSE;//先手 g_nSkill = 1;//棋力 g_nTimeLimit=60;//允许等待的最大时间 from 60 to 9000,单位秒 g_nIsNoTimeLimit=0;//限时 ready=0; } else { AfxMessageBox("未知错误!"); return; } } //以下部分是重新初始化 InitParams(); Invalidate(); UpdateWindow(); ShowNumber(1); SetChessTitle(); //设置菜单 m_pMenu->EnableMenuItem(IDM_HINT,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_UNDO,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED); PlaySounds(IDSOUND_NEWGAME); UpdateWindow(); SetWindowText(str); if (g_nRunMode==MODE_WITH_COMPUTER && !g_bUserBlack)//人机对站,机先走 {// Computer first,SO Computer is black!! CPoint pt; m_byColor = !m_byColor; // 1-Black 0-White,将前一对手的颜色变成当前对手的颜色 int ptBest_x,ptBest_y; IsEnd(m_byColor+1);//是否结束 Place(&ptBest_x,&ptBest_y,m_byColor+1); BtoW(ptBest_x,ptBest_y,m_byColor+1); AddStringToList(ptBest_x,ptBest_y,m_byColor); pt.x = ptBest_y*m_wStoneWidth + m_wXNull+m_wStoneWidth/2; pt.y = ptBest_x*m_wStoneHeight + m_wYNull+m_wStoneWidth/2; m_CurPt.x=ptBest_y; m_CurPt.y=ptBest_x; ClientToScreen(&pt); SetCursorPos(pt.x, pt.y); InvalidateRect(m_Client, FALSE); UpdateWindow(); PlaySounds(IDSOUND_PUTSTONE); } Ring(IsEnd(!m_byColor+1)); if(!m_bGameOver && g_bPeepOften) OnCanplace();//显示位置 SetTimer(PASSEDTIME,1000,NULL); m_TimerOn=1; m_nIsContinueReplay=1; } void CBWChessDlg::OnAbout() { CAboutDlg aboutDlg(this); aboutDlg.DoModal();//响应“关于黑白棋”菜单 } void CBWChessDlg::OnExit()//关闭程序 { if(m_TimerOn) KillTimer(PASSEDTIME); if(g_nIsDemo) ::TerminateThread(m_CcThread->m_hThread,0); CDialog::EndDialog(0); } void CBWChessDlg::PutStone(BYTE byColor, const CPoint &point, CDC *pDC)//填充棋格 { int nX = point.x*m_wStoneWidth + m_wXNull; int nY = point.y*m_wStoneHeight + m_wYNull; if (byColor == 0)// 0: WHITE 1 :BLACK DrawBitmap(pDC,nX,nY,IDB_WHITE, SRCCOPY); else if (byColor == 1) DrawBitmap(pDC,nX,nY,IDB_BLACK, SRCCOPY); } BOOL CBWChessDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {//响应光标事件 CPoint point, pt; ::GetCursorPos(&point); ScreenToClient(&point); if (PointToStonePos(point, pt) && !m_bGameOver && !g_nIsDemo) { //在棋盘内,显示 IDC_WHITE_HAND:IDC_BLACK_HAND 型 光标 // 0: WHITE 1 : BLACK,m_byColor代表前一个棋手的颜色,即还没有更新 ::SetCursor(AfxGetApp()->LoadCursor(m_byColor ? IDC_WHITE_HAND:IDC_BLACK_HAND)); return TRUE; } // 其他作默认处理 return CDialog::OnSetCursor(pWnd, nHitTest, message); } void CBWChessDlg::OnSysCommand(UINT nID, LPARAM lParam) { if(nID == SC_CLOSE) OnExit(); CDialog::OnSysCommand(nID, lParam); } void CBWChessDlg::OnContextMenu(CWnd* pWnd, CPoint point) //弹出菜单 { CRect rect; GetClientRect(&rect); CPoint pt=point; ScreenToClient(&pt); if(!rect.PtInRect (pt))//不在棋盘内 { CDialog::OnContextMenu (pWnd,point); return; } if(g_nIsDemo)//正在演示(不会用到,因为此时互斥!) return; CMenu menu; menu.LoadMenu(IDR_MENU_CONTEXT_CHINESE);//载入菜单 if(m_bGameOver) { menu.EnableMenuItem(IDM_UNDO, MF_GRAYED); menu.EnableMenuItem(IDM_HINT, MF_GRAYED); menu.EnableMenuItem(IDM_CANPLACE, MF_GRAYED); menu.EnableMenuItem(IDM_SAVEINFO,MF_ENABLED); menu.EnableMenuItem(IDM_REPLAY,MF_ENABLED); } if(!m_bGameOver) { menu.EnableMenuItem(IDM_SAVEINFO,MF_GRAYED); menu.EnableMenuItem(IDM_REPLAY,MF_GRAYED); } if(m_IsGameStart) menu.EnableMenuItem(IDM_SAVE, MF_GRAYED); menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, point.x, point.y, this);//弹出菜单 } ////////////////////////// End of BWCHESS.CPP //////////////////////////////// int CBWChessDlg::BtoW(int x1, int y1, int flag)//翻转棋子!!! { //x1 纵坐标 y1横坐标 int yes;//if yes ==0 then there is no position to change //if yes==1 then there is any position to change int temp=flag; int x=0,y=0,i=0,j=0; int result=0;//result==0 indicate that x1,y1 is the wrong position //result==1 indicate that they are legal position if(x1<0 || x1>=NUM || y1<0 || y1>=NUM)//棋子的位置在棋盘外面 return 0; //横向--当前左 x=x1; //y==0; yes=0; // kernel[NUM][NUM] : 0 for none,1 for white,2 for black for(i=y1-1;i>=0;i--) { if(kernel[x][i]==0) { yes=0; break; } else if(kernel[x][i]==temp) break; else yes=1; } if((i!=0-1) && (yes==1)) { for(i++;i<y1;i++) {// kernel[NUM][NUM] : 0 for none,1 for white,2 for black kernel[x][i]=temp;//temp代表当前棋手的颜色,将棋子翻成自己的颜色!! result=1; } } //横向--当前向右 //x==x1; //y==NUM; yes=0; for(i=y1+1;i<NUM;i++) { if(kernel[x][i]==0) { yes=0; break; } else if(kernel[x][i]==temp) break; else yes=1; } if((i!=NUM) && (yes==1)) { for(i--;i>y1;i--) {// kernel[NUM][NUM] : 0 for none,1 for white,2 for black kernel[x][i]=temp; result=1; } } //竖向--向上 //x==0; y=y1; yes=0; for(i=x1-1;i>=0;i--) { if(kernel[i][y]==0) { yes=0; break; } else if(kernel[i][y]==temp) break; else yes=1; } if((i!=0-1) && (yes==1)) { for(i++;i<x1;i++) {// kernel[NUM][NUM] : 0 for none,1 for white,2 for black kernel[i][y]=temp; result=1; } } //竖向--向下 //x==NUM; //y==y1; yes=0; for(i=x1+1;i<NUM;i++) { if(kernel[i][y]==0) { yes=0; break; } else if(kernel[i][y]==temp) break; else yes=1; } if((i!=NUM) && (yes==1)) { for(i--;i>x1;i--) { kernel[i][y]=temp; result=1; } } //斜向左上 //x==0; //y==y1; yes=0; for(i=x1-1,j=y1-1;(i>=0)&&(j>=0);i--,j--) { if(kernel[i][j]==0) { yes=0; break; } else if(kernel[i][j]==temp) break; else yes=1; } if((i!=0-1) && (j!=-1) && (yes==1)) { for(i++,j++;i<x1;i++,j++) { kernel[i][j]=temp; result=1; } } //斜向上向右 yes=0; for(i=x1-1,j=y1+1;(i>=0)&&(j<NUM);i--,j++) { if(kernel[i][j]==0) { yes=0; break; } else if(kernel[i][j]==temp) break; else yes=1; } if((i!=0-1) && (j!=NUM) && (yes==1)) { for(i++,j--;i<x1;i++,j--) { kernel[i][j]=temp; result=1; } } //斜向左下 yes=0; for(i=x1+1,j=y1-1;(i<NUM)&&(j>=0);i++,j--) { if(kernel[i][j]==0) { yes=0; break; } else if(kernel[i][j]==temp) break; else yes=1; } if((i!=NUM) && (j!=-1) && (yes==1)) { for(i--,j++;i>x1;i--,j++) { kernel[i][j]=temp; result=1; } } //斜向右下 yes=0; for(i=x1+1,j=y1+1;(i<NUM)&&(j<NUM);i++,j++) { if(kernel[i][j]==0) { yes=0;//无改动 break; } else if(kernel[i][j]==temp) break; else yes=1;//有改动 } if((i!=NUM) && (j!=NUM) && (yes==1)) { for(i--,j--;i>x1;i--,j--) { kernel[i][j]=temp; result=1; } } if(result==1) kernel[x1][y1]=temp; return result;//返回状态 1:OK,0:ERROR } int CBWChessDlg::IsEnd(/*int *x1, int *y1, */int whogo) {//whogo 1:代表黑色,2代表白色 int i,j;//行列坐标 int x,y; int wn=0,bn=0; //wn:代表白色可放棋子的个数,bn:代表黑色可放棋子的个数(本函数的功能1) int btp_x=-7,btp_y=-7,wtp_x=-7,wtp_y=-7; int temp,temp2; if(!wsp.isempty()) wsp.destroy();//先清空,再存储新的可下子的位置(本函数的功能2) if(!bsp.isempty()) bsp.destroy(); for(i=0;i<NUM;i++) for(j=0;j<NUM;j++) { if(kernel[i][j]==0) { //水平向左 if(Check(i,j-1) && Check(i,j-2))//没有越界且此位置有棋子 { x=i,y=j; temp=kernel[x][y-1]; for(y-=2;y>=0;y--) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j);//白色可放子的位置 } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j);//黑色可放子的位置 } } break; } } } //水平向右 if(Check(i,j+1) && Check(i,j+2)) { x=i,y=j; temp=kernel[x][y+1]; for(y+=2;y<NUM;y++) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j); } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j); } } break; } } } //垂直向上 if(Check(i-1,j) && Check(i-2,j)) { x=i,y=j; temp=kernel[x-1][y]; for(x-=2;x>=0;x--) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j); } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j); } } break; } } } //垂直向下 if(Check(i+1,j) && Check(i+2,j)) { x=i,y=j; temp=kernel[x+1][y]; for(x+=2;x<NUM;x++) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j); } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j); } } break; } } } //斜向左上 if(Check(i-1,j-1) && Check(i-2,j-2)) { x=i,y=j; temp=kernel[x-1][y-1]; for(x-=2,y-=2;(x>=0) && (y>=0);x--,y--) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j); } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j); } } break; } } } //斜向右上 if(Check(i-1,j+1) && Check(i-2,j+2)) { x=i,y=j; temp=kernel[x-1][y+1]; for(x-=2,y+=2;(x>=0) && (y<NUM);x--,y++) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j); } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j); } } break; } } } //斜向左下 if(Check(i+1,j-1) && Check(i+2,j-2)) { x=i,y=j; temp=kernel[x+1][y-1]; for(x+=2,y-=2;(x<NUM) && (y>=0);x++,y--) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j); } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j); } } break; } } } //斜向右下 if(Check(i+1,j+1) && Check(i+2,j+2)) { x=i,y=j; temp=kernel[x+1][y+1]; for(x+=2,y+=2;(x<NUM) && (y<NUM);x++,y++) { temp2=kernel[x][y]; if(temp2==0) break; if(temp2!=temp) { if(temp2==1) { if(wtp_x!=i || wtp_y!=j) { wtp_x=i,wtp_y=j; wn++; wsp.push (i,j); } } else { if(btp_x!=i || btp_y!=j) { btp_x=i,btp_y=j; bn++; bsp.push (i,j); } } break; } } } }//end if }//end second for if((bn==0) && (wn==0)) return -1;//return -1 for both if((bn>=2) && (wn>=2)) return 2;///return 2 for have more than one switch(whogo) { //whogo 1:代表黑色,2代表白色 case 1://代表黑色 if(wn==0) return 0;//return 0 for the int have no position break; case 2://2代表白色 if(bn==0) return 0;//return 0 for the int have no position break; } return 2;//return 2 for have more than one } int CBWChessDlg::Check(int x, int y) { if(x<0 || x>=NUM || y<0 || y>=NUM) return 0;//越界为0 if(kernel[x][y]==0) return 0;//无子为0 return 1; } int CBWChessDlg::Walk1(int *x1, int *y1, int flag)//寻找最佳位置给(x1,x2) { int fv=flag;//棋子颜色 2 黑 1 白 int k,n; if(fv==1)//1:白色 n=wsp.Len(); else// 2:黑色 n=bsp.Len(); srand( (unsigned)time( NULL ) ); k=rand()%n+1; //算法开始!! 本算法采用随机法 for(n=1;n<=k;n++) { if(fv==1)//1:白色 wsp.pop(x1,y1); else// 2:黑色 bsp.pop(x1,y1); //i,j是可以放棋子的坐标 } if(fv==1)//1:白色 wsp. destroy(); else// 2:黑色 bsp. destroy(); return 0; } void CBWChessDlg::Calcu_BW()//棋子计数 { int nw=0,nb=0; int i,j; for(i=0;i<NUM;i++) for(j=0;j<NUM;j++) if(kernel[i][j]==1) nw++; else if(kernel[i][j]==2) nb++; num_black=nb; num_white=nw; } int CBWChessDlg::IsInPanel(CPoint &pt)//判断是否在棋盘上 { if(pt.x<=m_wXNull || pt.x>=(m_wXNull + NUM*m_wStoneWidth)) return 0; if(pt.y<=m_wYNull || pt.y>=(m_wYNull + NUM*m_wStoneHeight)) return 0; return 1; } void CBWChessDlg::ShowNumber(int isTime)//刷新 时间和棋子的个数 { BCount.SetNumber(num_black); WCount.SetNumber(num_white); if(isTime) { TimeCount.SetNumber(m_PassedTime); TimeCount0.SetNumber(m_PassedTime0); } } void CBWChessDlg::OnTimer(UINT nIDEvent) //计时 { if(nIDEvent==PASSEDTIME)//尚未更新 { if(!m_byColor)//白色 m_PassedTime++; else//黑色 m_PassedTime0++; ShowNumber(1);//“1”代表时间也要刷新 if(g_nRunMode == MODE_2PLAYER && !g_nIsNoTimeLimit)//人对人,限时 { if((m_PassedTime>=g_nTimeLimit) || (m_PassedTime0>=g_nTimeLimit)) {//超时!!游戏结束 m_bGameOver=TRUE; if(m_TimerOn) { KillTimer(PASSEDTIME); m_TimerOn=0; } m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED); AddStringToList(0,0,0,(m_PassedTime>=g_nTimeLimit)? 1 : 2); PlaySounds(IDSOUND_USERWIN); //弹出游戏结束的对话框 MsgBox((m_PassedTime>=g_nTimeLimit)? IDS_BLACK_LIMIT : IDS_WHITE_LIMIT ,IDS_TITLE_CHINESE); } } } CDialog::OnTimer(nIDEvent); } void CBWChessDlg::OnUndo() { if(g_nRunMode==MODE_NETWORK)//网络2 { AfxMessageBox("你不能作弊!"); return; } m_PeekOnce=0; if(m_UndoPoint.IsEmpty())//已为空,m_UndoPoint的类名是 Cundo { PlaySounds(IDSOUND_ERROR); MsgBox(IDS_CANNOT_UNDO1_CHINESE, IDS_TITLE_CHINESE);//弹出无法悔棋的对话框 return; } if (m_bGameOver) return; int c1,c2,i,j,k=0; c1=m_UndoPoint.GetTopColor();//获取颜色 int temp[NUM*NUM]; m_UndoPoint.pop(temp);//获取棋盘 RemoveStringFromList(); if(g_nRunMode == MODE_WITH_COMPUTER)//人机对战 { if(c1==m_byColor) { while(!m_UndoPoint.IsEmpty()) { c2=m_UndoPoint.GetTopColor(); RemoveStringFromList(); if(c1!=c2) { m_UndoPoint.pop(temp); break; } else { int again_pop[NUM*NUM]; m_UndoPoint.pop(again_pop); } }// end while }//end if } else { if(m_UndoPoint.IsEmpty()) { if(g_bUserBlack) m_byColor=0; else m_byColor=1; } else { m_byColor=m_UndoPoint.GetTopColor (); } } for(i=0;i<NUM;i++) for(j=0;j<NUM;j++) { kernel[i][j]=temp[k]; k++; } IsEnd(!m_byColor+1); if(!m_bGameOver && g_bPeepOften) OnCanplace(); m_HintOnce=0; Calcu_BW(); ShowNumber(); PlaySounds(IDSOUND_UNDO); InvalidateRect(m_Client, TRUE); UpdateWindow(); } void CBWChessDlg::duplicate()//保存当前棋盘和当前颜色,为悔棋作准备 { int temp[NUM*NUM]; int i,j,k=0; for(i=0;i<NUM;i++) for(j=0;j<NUM;j++) temp[k++]=kernel[i][j]; m_UndoPoint.push(temp,m_byColor); } void CBWChessDlg::Place(int *x, int *y,int color) {//获取最佳位置 int mx=0,my=0; Walk1(&mx,&my,color); *x=mx; *y=my; } void CBWChessDlg::OnBest() //显示英雄榜 { CBestDlg bestDlg; bestDlg.DoModal(); } void CBWChessDlg::OnHint() // 响应“提示” { const int HINTSIZE=7; if (m_bGameOver) return; if(m_HintOnce) return; if(g_nRunMode == MODE_2PLAYER)//人对人 { if(((m_HintTime0>=g_nCanHintTimeW) && m_byColor) || ((m_HintTime1>=g_nCanHintTimeB) && !m_byColor)) { CString str1,str2; TCHAR s[200]; str1.LoadString(IDS_MORETHANTHREE_CHINESE);//代表“我已提示了你%d次,不能再提示了!” str2.LoadString(IDS_TITLE_CHINESE);//代表“黑白棋” if(m_HintTime0>=g_nCanHintTimeW) wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeW); else wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeB); CString str(s); MsgBox(str,str2);//给出对话框 return;// 退出提示 } if(m_byColor)//次数累加 m_HintTime0++; else m_HintTime1++; } else // 人对机 { if(m_HintTime0>=g_nCanHintTimeW || m_HintTime1>=g_nCanHintTimeB)//0 白 1黑 { CString str1,str2; TCHAR s[200]; str1.LoadString(IDS_MORETHANTHREE_CHINESE); str2.LoadString(IDS_TITLE_CHINESE); if(m_HintTime0>=g_nCanHintTimeW) wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeW); else wsprintf(s,str1.GetBuffer(256),g_nCanHintTimeB); CString str(s); MsgBox(str,str2); return; } else { if(m_byColor) m_HintTime0++; else m_HintTime1++; } } int px,py; Walk1(&py,&px,!m_byColor+1);//寻找最佳点 x1 = px*m_wStoneWidth + m_wXNull-HINTSIZE + m_wStoneWidth / 2; y1 = py*m_wStoneHeight + m_wYNull-HINTSIZE + m_wStoneHeight / 2; x2 = px*m_wStoneWidth + m_wXNull+HINTSIZE + m_wStoneWidth / 2; y2 = py*m_wStoneHeight + m_wYNull+HINTSIZE + m_wStoneHeight / 2; //矩形:(x1,y1,x2,y2) CClientDC dc(this);//画 “X" COLORREF crColor = m_byColor ? RGB(255,255,255) : RGB(0,0,0);//1 画 白 CPen pen(PS_SOLID, 2, crColor); CPen *pOldPen = dc.SelectObject(&pen); dc.MoveTo(x1, y1); dc.LineTo(x2, y1); dc.LineTo(x2, y2); dc.LineTo(x1, y2); dc.LineTo(x1, y1); dc.LineTo(x2, y2); dc.MoveTo(x2, y1); dc.LineTo(x1, y2); dc.SelectObject(pOldPen); m_HintOnce=1; } void CBWChessDlg::MoveCursor(int x, int y) {//从当前(m,n)位置向(x,y)走,x,y 是以像素为单位的,所使用的平面是窗口平面 //每次移动鼠标之前,系统都会根据 m_byColor 的值载入光标,0载入黑手,1载入白手,之所以相反(0白1黑), //是因为系统载入光标时,用户还没有点击棋盘,m_byColor代表的前一个棋手的颜色。 //但是本函数在调用时,m_byColor代表的是当前棋手的颜色 //轮流到计算机下时,在计算机下棋之前,由于计算机不移动鼠标,也不敲击键盘,因此光标不会更新, //仍使用前一个棋手的光标,故在此处必须修正!! m_byColor=!m_byColor; ::SetCursor(AfxGetApp()->LoadCursor(m_byColor ? IDC_WHITE_HAND:IDC_BLACK_HAND));//修正部分 m_byColor=!m_byColor; if(!g_bMovePlace) { return; } CPoint pt; GetCursorPos(&pt); int m,n; int sleep_interval=2; m=pt.x ; n=pt.y ; if(m >x) { while(m>x)//向左走 { m-=g_nMoveSpeeds; Sleep(sleep_interval); SetCursorPos(m,n); } } else if(m<x)//向右走 { while(m<x) { m+=g_nMoveSpeeds; Sleep(sleep_interval); SetCursorPos(m,n); } } if(n >y) { while(n>y)//向上走 { n-=g_nMoveSpeeds; Sleep(sleep_interval); SetCursorPos(m,n); } } else if(n < y)//向下走 { while(n < y) { n+=g_nMoveSpeeds; Sleep(sleep_interval); SetCursorPos(m,n); } } } void CBWChessDlg::OnCanplace() //本函数计算当前棋手可下的位置,并标志出来!(X) { if (m_bGameOver) return; if(m_PeekOnce) return; int px,py; int xx1,yy1; int length,hy; //CClientDC dc(this);; CDC *dc=GetDC(); if(m_byColor)//判断是否有位置可填 length=wsp.isempty(); else length=bsp.isempty(); if(length)//无,结束 return; do { if(m_byColor) length=wsp.GetNextPos(&py,&px,&hy); else length=bsp.GetNextPos(&py,&px,&hy); xx1 = px*m_wStoneWidth + m_wXNull;//-4 + m_cxGrid / 2; yy1 = py*m_wStoneHeight + m_wYNull;//-4 + m_cyGrid / 2; if(m_byColor) DrawBitmap(dc,xx1,yy1,IDB_CANPLACE2, SRCCOPY); else DrawBitmap(dc,xx1,yy1,IDB_CANPLACE1, SRCCOPY); }while(length); if(m_byColor) wsp.CopyBackIndex(); else bsp.CopyBackIndex(); m_PeekOnce=1; ReleaseDC(dc); } void CBWChessDlg::OnSetting() //响应“设置”命令 { CSettingDlg dlg; dlg.DoModal ();//显示“设置”对话框 if(g_bTopMost) SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); else SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); } void CBWChessDlg::OnOpen() //响应“OPEN”命令 { if(!m_bGameOver && g_bPrompt) if(MsgBox(IDS_ABORT,IDS_TITLE_CHINESE,2)==IDCANCEL) return ; TCHAR sFilter[50]="BWChess File (*.BWS)|*.BWS||"; CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, sFilter); int result=dlg.DoModal(); if(result==IDOK) { CFile file(dlg.GetPathName(), CFile::modeRead); int buffer[9000],len,t; unsigned int reallen=file.Read(buffer,9000*sizeof(int)); if((reallen!=(buffer[0]*sizeof(int))) || (reallen<140)) { MsgBox(IDS_OPENERROR1,IDS_TITLE_CHINESE); return; } if(buffer[1]!=EDITION) { MsgBox(IDS_OPENERROR2,IDS_TITLE_CHINESE); return; } if(buffer[2]) { MsgBox(IDS_OPENERROR3,IDS_TITLE_CHINESE); return; } int i,j; len=buffer[0]/2-1; BOOL changeI=FALSE; for(t=0;t<len;t++) { if(buffer[t+3]!=buffer[3+len+t]) { changeI=TRUE; break; } } if(changeI) { MsgBox(IDS_OPENERROR1,IDS_TITLE_CHINESE); return; } if(m_TimerOn) { KillTimer(PASSEDTIME); m_TimerOn=0; } m_bGameOver = FALSE; m_Skip=0; i=0; g_nStoneNum=0; m_HintOnce=0;//0 for have not hinted yet,1 for have hinted m_PeekOnce=g_bPeepOften; m_IsGameStart=0; ListInfo.destroy(); m_ListInfo.ResetContent(); if(!m_UndoPoint.IsEmpty()) m_UndoPoint.Destroy(); len=3;///important m_byColor=buffer[len++]; g_nRunMode=buffer[len++]; m_PassedTime=buffer[len++]; m_PassedTime0=buffer[len++]; g_nSkill=buffer[len++]; g_bUserBlack=buffer[len++]; m_HintTime0=buffer[len++]; m_HintTime1=buffer[len++]; g_nTimeLimit=buffer[len++]; g_nIsNoTimeLimit=buffer[len++]; len+=5; for(i=0;i<NUM;i++) for(j=0;j<NUM;j++) kernel[i][j]=buffer[len++]; int x,y,num,tc; num=buffer[len++]; while(num>0) { x=buffer[len++]; y=buffer[len++]; tc=buffer[len++]; AddStringToList(x,y,tc); num--; } //read m_UndoPoint num=buffer[len++]; while(num>0) { int temp[NUM*NUM]; for(x=0;x<NUM*NUM;x++) temp[x]=buffer[len++]; tc=buffer[len++]; m_UndoPoint.push(temp,tc); num--; } IsEnd(1); Calcu_BW(); SetChessTitle(); m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_HINT,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_UNDO,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED); InvalidateRect(NULL,TRUE); SetTimer(PASSEDTIME,1000,NULL); m_TimerOn=1; } } void CBWChessDlg::OnSave() //响应“SAVE”命令 { TCHAR sFilter[50]=_T("BWChess File (*.BWS)|*.BWS||"); TCHAR sExt[10]=_T("BWS"); CFileDialog dlg(FALSE,sExt,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, sFilter); if(dlg.DoModal()==IDOK) { CFile file(dlg.GetPathName(),CFile::modeCreate | CFile::modeWrite); int buffer[9000],len=3;// the buffer need about 4000 size for(int ii=0;ii<2;ii++)//copy twice { buffer[len++]=m_byColor; buffer[len++]=g_nRunMode; buffer[len++]=m_PassedTime; buffer[len++]=m_PassedTime0; buffer[len++]=g_nSkill; buffer[len++]=g_bUserBlack; buffer[len++]=m_HintTime0; buffer[len++]=m_HintTime1; buffer[len++]=g_nTimeLimit; buffer[len++]=g_nIsNoTimeLimit; //restore 5 position for future use buffer[len++]=0; buffer[len++]=0; buffer[len++]=0; buffer[len++]=0; buffer[len++]=0; int i,j; for(i=0;i<NUM;i++) for(j=0;j<NUM;j++) buffer[len++]=kernel[i][j]; int num=ListInfo.Len(); buffer[len++]=num; int x,y,tc; int re; stack ts; do { re=ListInfo.GetNextPos(&x,&y,&tc); ts.push(x,y); ts.SetMarks (tc); } while(re); do { re=ts.GetNextPos(&x,&y,&tc); buffer[len++]=x; buffer[len++]=y; buffer[len++]=tc; } while(re); ListInfo.CopyBackIndex(); // store m_UndoPoint int tlen=m_UndoPoint.Len(); buffer[len++]=tlen; int tempUndo[NUM*NUM]; do { re=m_UndoPoint.GetNextPos(tempUndo,&tc); for(x=0;x<NUM*NUM;x++) buffer[len++]=tempUndo[x]; buffer[len++]=tc; } while(re); m_UndoPoint.CopyBackIndex(); } buffer[0]=len; buffer[1]=EDITION;//this the edition of the banben buffer[2]=(int)m_bGameOver; file.Write(buffer,len*sizeof(int)); } } void CBWChessDlg::AddStringToList(int x, int y, int color,int win)//加入信息于列表框 { CString str; int result=m_ListInfo.GetCount(); if(!win) { if(color) str.LoadString(IDS_SBLACK);// “%2d.黑棋: %c %d” else str.LoadString(IDS_SWHITE); TCHAR s[100]; wsprintf(s, str.GetBuffer(256),result+1, y+65,x+1); m_ListInfo.AddString(s); ListInfo.push(x,y); ListInfo.SetMarks(color); } else { if(win==1)//白 win str.LoadString(IDS_WHITEWIN_CHINESE); else if(win==2)//黑 win str.LoadString(IDS_BLACKWIN_CHINESE); else//本局平局 str.LoadString(IDS_TIE); m_ListInfo.AddString(str); } m_ListInfo.SetCurSel(result);//将当前新加入的显色(兰色) m_ListInfo.SetFocus(); } void CBWChessDlg::RemoveStringFromList()//于列表框删除信息 { int index=m_ListInfo.GetCount(); m_ListInfo.DeleteString(index-1); int x,y; ListInfo.pop(&x,&y); ListInfo.GetTop(x,y); m_CurPt.x =x,m_CurPt.y=y; index=m_ListInfo.GetCount(); if(index) { m_ListInfo.SetCurSel(index-1); m_ListInfo.SetFocus(); } } void CBWChessDlg::OnSaveinfo() //响应“导出走棋信息” { TCHAR sFilter[50]=_T("文本文件(*.TXT)|*.TXT||"); TCHAR sExt[10]=_T("txt"); CFileDialog dlg(FALSE,sExt,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, sFilter); if(dlg.DoModal()==IDOK) { CFile file(dlg.GetPathName(),CFile::modeCreate | CFile::modeWrite | CFile::typeText); TCHAR buffer[300]; int len=0,index=0; len=GetWindowText(buffer,300); buffer[len++]=13; buffer[len++]=10; file.Write(buffer,len); len=m_ListInfo.GetCount(); while(index<len) { int slen=m_ListInfo.GetText(index++,buffer); buffer[slen]=13; buffer[slen+1]=10; file.Write(buffer,slen+2); } } } BOOL CBWChessDlg::PreTranslateMessage(MSG* pMsg) //检测加速键消息是否被处理了 {//The TranslateAccelerator function processes accelerator keys for menu commands if(!::TranslateAccelerator(m_hWnd,hAccelerator, pMsg)) return CDialog::PreTranslateMessage(pMsg); return TRUE; } void CBWChessDlg::SetChessTitle()//载入标题 { CString str; if (g_nRunMode==MODE_WITH_COMPUTER && g_bUserBlack) str.LoadString(IDS_SINGLE_USER_CHINESE);//“黑白棋: 与计算机对弈, 你执黑先下” else if (g_nRunMode==MODE_WITH_COMPUTER && !g_bUserBlack) str.LoadString(IDS_SINGLE_COMPUTER_CHINESE);//“黑白棋: 与计算机对弈, 计算机执黑先下” else if (g_nRunMode==MODE_2PLAYER) { if(g_nIsNoTimeLimit) str.LoadString(IDS_DOUBLE_NOLIMIT_CHINESE);//“黑白棋: 双人同机对弈,不限时” else { str.LoadString(IDS_DOUBLE_LIMIT_CHINESE);//“黑白棋: 双人同机对弈,限时%d秒” TCHAR str1[200]; wsprintf(str1, str.GetBuffer(256), g_nTimeLimit); str=str1; } } SetWindowText(str);//显示标题 } void CBWChessDlg::OnListDoubleClicked()//双击列表,撤消操作 { if(m_bGameOver || g_nIsDemo)//游戏已结束或正在演示 return; int nSel=m_ListInfo.GetCurSel(); int length=m_ListInfo.GetCount()-1; while(length>=nSel)//依次进行撤消 { OnUndo(); length=m_ListInfo.GetCount()-1; } } void CBWChessDlg::DrawFrame(CDC *dc)//画棋盘 { const int Sx=1; const int Sy=1; int i,j; int wx0,wy0,wx1,wy1; wx0=Sx,wy0=Sy; DrawBitmap(dc,wx0,wy0,IDB_F1_1,SRCCOPY); wx0=Sx+m_wFrameHeight+NUM*m_wFrameWidth,wy0=Sy; DrawBitmap(dc,wx0,wy0,IDB_F1_10,SRCCOPY); wx0=Sx,wy0=Sy+m_wFrameHeight+NUM*m_wStoneHeight; DrawBitmap(dc,wx0,wy0,IDB_F10_1,SRCCOPY); wx0=Sx+m_wFrameHeight+NUM*m_wStoneWidth,wy0=Sy+m_wFrameHeight+NUM*m_wStoneHeight; DrawBitmap(dc,wx0,wy0,IDB_F10_10,SRCCOPY); wx0=Sx+m_wFrameHeight,wy0=Sy,wx1=Sx+m_wFrameHeight,wy1=Sy+m_wFrameHeight+m_wStoneWidth*NUM; for(i=1,wx0=Sx+m_wFrameHeight,wy0=Sy,wx1=Sx+m_wFrameHeight,wy1=Sy+m_wFrameHeight+m_wStoneWidth*NUM;i<NUM+1;i++) {//画水平的边框8格 DrawBitmap(dc,wx0,wy0,IDB_F1_2+i-1,SRCCOPY); DrawBitmap(dc,wx1,wy1,IDB_F10_2+i-1,SRCCOPY); wx0+=m_wFrameWidth; wx1+=m_wFrameWidth; } for(i=0,wx0=Sx,wy0=Sy+m_wFrameHeight,wx1=Sx+m_wFrameHeight+NUM*m_wStoneWidth,wy1=Sy+m_wFrameHeight;i<NUM;i++) {//画垂直的边框8格 DrawBitmap(dc,wx0,wy0,IDB_F2_1+i,SRCCOPY); DrawBitmap(dc,wx1,wy1,IDB_F2_10+i,SRCCOPY); wy0+=m_wStoneHeight; wy1+=m_wStoneHeight; } for(i=0,wx0=Sx+m_wFrameHeight,wy0=Sy+m_wFrameHeight;i<NUM;i++,wx0=Sx+m_wFrameHeight,wy0=i*m_wStoneHeight+Sy+m_wFrameHeight) for(j=0;j<NUM;j++,wx0+=m_wStoneWidth) {//画棋盘8*8 if(!kernel[i][j]) { CPoint pt(wx0,wy0); DrawBitmap(dc,wx0,wy0,IDB_EMPTY,SRCCOPY); } } } void CBWChessDlg::OnDemo() //响应“计算机演示/终止计算机对弈”命令 { CString str; if(g_nIsDemo)//响应“终止计算机对弈”命令 { ::TerminateThread(m_CcThread->m_hThread,0); m_pMenu->EnableMenuItem(IDM_NEW,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_OPEN,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_REPLAY,MF_ENABLED); str.LoadString(IDS_DEMOTITLE0);//“计算机演示[&M]...\tCtrl+M” m_pMenu->ModifyMenu(IDM_DEMO,MF_BYCOMMAND | MF_STRING,IDM_DEMO,str); //程序已经在“演示”,菜单已被改为“终止计算机对弈”,因此现在要恢复为“计算机演示” g_nIsDemo=0; m_bGameOver=TRUE; } else//响应“计算机演示”命令 { int HaveKilled=0; if(m_TimerOn)//终止计时 { HaveKilled=1; KillTimer(PASSEDTIME); m_TimerOn=0; } if(!m_bGameOver && g_bPrompt)//游戏没有结束 { if(MsgBox(IDS_ABORT,IDS_TITLE_CHINESE,2)==IDCANCEL) {//弹出对话框询问 if(HaveKilled)//取消对话框,恢复计时 { SetTimer(PASSEDTIME,1000,NULL); m_TimerOn=1; } return; } } //OK对话框 CDemo dlg;//弹出计算机对弈对话框 if(dlg.DoModal()==IDCANCEL) { if(HaveKilled) { SetTimer(PASSEDTIME,1000,NULL); m_TimerOn=1; } return; } //修改菜单 m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_SAVE,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_NEW,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_OPEN,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_REPLAY,MF_GRAYED); str.LoadString(IDS_DEMOTITLE1); m_pMenu->ModifyMenu(IDM_DEMO,MF_BYCOMMAND | MF_STRING,IDM_DEMO,str); //修改菜单为“终止计算机对弈” int flag=0;//标志是否为历史棋局 if(dlg.m_IsFile)//演示历史棋局 { CFile file(dlg.m_FilePath, CFile::modeRead); int buffer[9000],len; file.Read(buffer,9000*sizeof(int)); len=18+NUM*NUM;///important m_PointGo.destroy(); int x,y,num,tc; stack tt; num=buffer[len++];//num代表走棋的步数 while(num>0)//进栈 { x=buffer[len++]; y=buffer[len++]; tc=buffer[len++]; tt.push(x,y); tt.SetMarks(tc); num--; } while(!tt.isempty ())//再出栈入栈,顺序演示 { tc=tt.GetMarks (0); tt.pop (&x,&y); m_PointGo.push(x,y); m_PointGo.SetMarks(tc); } flag=0; } else//不是历史棋局 { CString str1; switch(g_nCbSkill)//黑方级别 { case 1://黑方:初级 switch(g_nCwSkill)//白方级别 { case 1://白方:初级 str1.LoadString(IDS_DEMO_TITLE_11); //“黑白棋:计算机演示->黑方:初级;白方:初级” break; case 2://白方:中级 str1.LoadString(IDS_DEMO_TITLE_12); //黑白棋:计算机演示->黑方:初级;白方:中级 break; case 3://白方:专家级 str1.LoadString(IDS_DEMO_TITLE_13); //黑白棋:计算机演示->黑方:初级;白方:专家级 break; } break; case 2://黑方:中级 switch(g_nCwSkill) { case 1: str1.LoadString(IDS_DEMO_TITLE_21); //黑白棋:计算机演示->黑方:中级;白方:初级 break; case 2: str1.LoadString(IDS_DEMO_TITLE_22); break; case 3: str1.LoadString(IDS_DEMO_TITLE_23); break; } break; case 3://黑方:高级 switch(g_nCwSkill) { case 1: str1.LoadString(IDS_DEMO_TITLE_31); break; case 2: str1.LoadString(IDS_DEMO_TITLE_32); break; case 3: str1.LoadString(IDS_DEMO_TITLE_33); break; } break; } SetWindowText(str1);//设置标题,显示设置的信息 flag=1; } g_nIsDemo=1; m_DemoOrReplay=1; m_CcThread=AfxBeginThread(CCplayFunc,(LPVOID )flag,THREAD_PRIORITY_NORMAL, 0,CREATE_SUSPENDED); //创建一线程,对应的函数是 CCplayFunc(LPVOID p),优先级别NORMAL,阻塞状态 m_Mutex.Lock();//互斥,不再响应棋盘上的点击事件 m_CcThread->ResumeThread(); //执行线程 } m_nIsContinueReplay=1; } UINT CCplayFunc(LPVOID p)//CCplayFunc(LPVOID p) 是CBWChessDlg类的友员函数 { CBWChessDlg *dlg=(CBWChessDlg *)(AfxGetApp()->m_pMainWnd); //m_pMainWnd 指向主界面 dlg->ComputerPlay ((int)p);//在子线程中执行计算机演示操作,主线程仍可响应用户输入 return 0; } void CBWChessDlg::ComputerPlay(int flag)//计算机演示对弈 { InitParams(); IsEnd(m_byColor+1); m_PeekOnce=(int)g_bPeepOften; Mutex1.Lock(); g_nMutex=1;//确保此操作能一次性完成 Mutex1.Unlock(); InvalidateRect(&m_Client, FALSE); m_Mutex.Lock();//锁定棋盘 while(1) { m_byColor = !m_byColor; //棋手交换 // 1-Black 0-White int ptBest_x=0,ptBest_y=0,result=0,ret=0; if(flag)//无历史型的演示(级别无效) { if(m_byColor) Place(&ptBest_x,&ptBest_y,m_byColor+1); else Place(&ptBest_x,&ptBest_y,m_byColor+1); } else//有历史型的演示 {///add here从栈里获得数据 ret=m_PointGo.GetNextPos(&ptBest_x,&ptBest_y,&m_byColor); } BtoW(ptBest_x,ptBest_y,m_byColor+1); Calcu_BW();// 计算黑白棋子的数目 result=IsEnd(!m_byColor+1); Mutex1.Lock(); g_nMutex=1; Mutex1.Unlock(); InvalidateRect(&m_Client, FALSE); UpdateWindow(); m_Mutex.Lock(); AddStringToList(ptBest_x,ptBest_y,m_byColor); PlaySounds(IDSOUND_PUTSTONE); if(!ret && !flag) { m_bGameOver=TRUE; break; } if(result==-1)//演示结束 { CString str1,str2,str3,strPrompt; TCHAR str[300]; int addp=0; m_bGameOver=TRUE; Calcu_BW(); str2.LoadString (IDS_TITLE_CHINESE);//“黑白棋” if(num_white<num_black) {//本局黑棋胜。 addp=2; str1.LoadString(IDS_BLACKWIN_CHINESE); } else if(num_white>num_black) {//本局白棋胜。 addp=1; str1.LoadString(IDS_WHITEWIN_CHINESE); } else {//“本局平手。\n我们的水平不分上下!” addp=3; str1.LoadString(IDS_TIE_CHINESE); } str3.LoadString(IDS_END_CHINESE); //“黑棋%d子,白棋%d子” wsprintf(str, str3.GetBuffer(256), num_black,num_white); strPrompt = str; strPrompt += str1; AddStringToList(0,0,0,addp); Mutex1.Lock(); g_nMutex=1; Mutex1.Unlock(); InvalidateRect(&m_Client,FALSE); m_Mutex.Lock(); PlaySounds(IDSOUND_USERWIN); MsgBox(strPrompt,str2);//弹出显示演示结果的对话框 break; } else if(result==0)//当前一方不能下,换下一方 m_byColor=!m_byColor;//轮流 Sleep(500*g_nCSpeed);//减慢演示速度 }//end while CString strT; m_pMenu->EnableMenuItem(IDM_NEW,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_OPEN,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_ENABLED); if(m_DemoOrReplay) { strT.LoadString(IDS_DEMOTITLE0);//修改为“计算机演示[&M]...\tCtrl+M” m_pMenu->ModifyMenu(IDM_DEMO,MF_BYCOMMAND | MF_STRING,IDM_DEMO,strT); m_pMenu->EnableMenuItem(IDM_REPLAY,MF_ENABLED);//使“重温棋局”有效 } else {//add here strT.LoadString(IDS_REPLAY0);//“重温棋局[&W]\tCtrl+W” m_pMenu->ModifyMenu(IDM_REPLAY,MF_BYCOMMAND | MF_STRING,IDM_REPLAY,strT);//"重温棋局" m_pMenu->EnableMenuItem(IDM_DEMO,MF_ENABLED); } g_nIsDemo=0; m_PointGo.CopyBackIndex(); } void CBWChessDlg::OnReplay() //响应“重温棋局” { CString str; if(g_nIsDemo)//正在演示 { ::TerminateThread(m_CcThread->m_hThread,0);//终止演示线程 m_pMenu->EnableMenuItem(IDM_NEW,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_OPEN,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_SAVE,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_ENABLED); m_pMenu->EnableMenuItem(IDM_DEMO,MF_ENABLED); str.LoadString(IDS_REPLAY0);//“重温棋局[&W]\tCtrl+W” m_pMenu->ModifyMenu(IDM_REPLAY,MF_BYCOMMAND | MF_STRING,IDM_REPLAY,str); g_nIsDemo=0; m_bGameOver=TRUE; m_PointGo.CopyBackIndex(); } else//没有演示 { int HaveKilled=0; if(m_TimerOn) { HaveKilled=1; KillTimer(PASSEDTIME); m_TimerOn=0; } if(!m_bGameOver && g_bPrompt)//游戏没有结束 { if(MsgBox(IDS_ABORT,IDS_TITLE_CHINESE,2)==IDCANCEL) //“你确定要终止当前的对局吗?”“黑白棋” {//继续 if(HaveKilled) { SetTimer(PASSEDTIME,1000,NULL); m_TimerOn=1; } return; } } m_pMenu->EnableMenuItem(IDM_HINT,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_UNDO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_CANPLACE,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_SAVE,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_SAVEINFO,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_NEW,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_OPEN,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_NETPLAY,MF_GRAYED); m_pMenu->EnableMenuItem(IDM_DEMO,MF_GRAYED); str.LoadString(IDS_REPLAY1);//载入“终止重温棋局[&W]\tCtrl+W” m_pMenu->ModifyMenu(IDM_REPLAY,MF_BYCOMMAND | MF_STRING,IDM_REPLAY,str); //duplicate stack if(m_nIsContinueReplay) { m_PointGo.destroy(); while(!ListInfo.isempty())//将序列倒置,存入m_PointGo 栈中!! { int x,y,mark; mark=ListInfo.GetMarks(0); ListInfo.pop(&x,&y); m_PointGo.push(x,y); m_PointGo.SetMarks(mark); } m_nIsContinueReplay=0;//防止第二次赋值 } g_nIsDemo=1;//开始演示标志 m_DemoOrReplay=0; m_CcThread=AfxBeginThread(CCplayFunc,(LPVOID)0,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED); //派生演示线程,设置为历史棋盘“演示模式”,由“(LPVOID)0”表示 m_Mutex.Lock();//互斥地演示 m_CcThread->ResumeThread(); //开始演示! } } void AcceptCallback (DWORD ptr)//接受连接的处理函数 { CNetworking* net = reinterpret_cast <CNetworking*> (ptr); if (Connection && Connection->IsConnected ())//清除多余的连接,但保留当前的连接 { CConnection* c = net->GetAccepted (); while (c) { char nocon[] = "The host can not accept your connection at this time."; c->Send (nocon, sizeof (nocon)); c->Disconnect (); delete c; c = net->GetAccepted (); } } else//没有连接,接受连接 { if (Connection) delete Connection; Connection = net->GetAccepted ();//接受连接对象 Connection->SetReceiveFunc (ReceiveCallback);//设置数据到达时的回调函数 Connection->SetCloseFunc (CloseCallback);//设置连接关闭时要调用的回调函数 AfxMessageBox("有人加入,连接成功,你先下"); Sever=1;//设置为服务器模式 } } UINT ReceiveFunc(int kk)//数据到达时的处理函数,是友员函数!!!!!! { CBWChessDlg *dlg=(CBWChessDlg *)(AfxGetApp()->m_pMainWnd); if(kk!=10)//所有数据大于等于10,大于10是其他消息,等于10 是走棋消息,只用到前面3个字节,其他7个备用 { szBuff[10]='\0'; szBuff[0]='#'; AfxMessageBox("不是所要的数据"); char str[1000]; wsprintf(str,"%s",szBuff); AfxMessageBox(str); return 0; } if((szBuff[0]-48)==CMD_RESIGN) { AfxMessageBox("对手退出了"); m_bGameOver=TRUE; return 0; } if((szBuff[0]-48)==CMD_OVER) { pppp=100; } if((szBuff[0]-48)==CMD_SKIP) { dlg->m_Skip=1; } if(m_bGameOver) return 1; int x=szBuff[1]-48; int y=szBuff[2]-48; if(m_bGameOver==false) dlg->Newchess(x,y); //销毁数据 dlg=NULL; return 1; } void ReceiveCallback (DWORD ptr)//数据到达时的处理 { CConnection* c = reinterpret_cast <CConnection*> (ptr); int kk=c->Receive (szBuff, 1000);//接受数据 ReceiveFunc(kk);//相关的数据处理函数 } void CloseCallback (DWORD ptr)//关闭连接 { AfxMessageBox ("The connection was closed."); if (Connection) delete Connection;//关闭连接 Connection=NULL; if(Sever==1)//为服务器 { Networking.StopListen (); Networking.Listen(10205); } if(g_nRunMode==MODE_NETWORK)//网络模式 m_bGameOver=true;//游戏结束 Sever=2;//非网络模式 ptr=ptr+0; } UINT ConnectFunc(LPVOID flag)//与主机进行连接的线程函数 { Cip m_ip;//创建IP对话框 if (m_ip.DoModal()==IDCANCEL)//取消了 return (UINT)flag; BYTE IP1=m_ip.IP1; BYTE IP2=m_ip.IP2; BYTE IP3=m_ip.IP3; BYTE IP4=m_ip.IP4; char IP[16]; wsprintf(IP,"%d.%d.%d.%d",IP1,IP2,IP3,IP4); AfxMessageBox(IP); int i=0; while(i<10&&Connection->Connect (IP, 10205)!=true) { i++; Sleep(100); } if(i<10) { AfxMessageBox("连接成功,对手先下"); Sever=0;//只有在连接之后才能设置客户机模式 } else { AfxMessageBox("连接失败"); Sever=2; } return (UINT)flag; } void CBWChessDlg::OnConnect()//建立客户机 { if(Sever==1||Sever==0) { AfxMessageBox("已经建立了连接,请先断开连接"); return; } Sever=2;//设为非连网模式 Connection = new CConnection ();//建立连接对象 AfxBeginThread(ConnectFunc,0,THREAD_PRIORITY_NORMAL,0,NULL);//连接到服务器 Connection->SetReceiveFunc(ReceiveCallback);//建立连接对象,设置数据到达时的回调函数 Connection->SetCloseFunc (CloseCallback);//设置连接被关闭时的回调函数 } void CBWChessDlg::OnHost()//建立服务器 { if(Sever==1) { AfxMessageBox("已经建立了,不能重复建立"); return; } if(Sever==0) { AfxMessageBox("已经建立了连接,请先断开连接"); return; } Sever=2;//设为非连网模式 if(Networking.Listen(10205)) { AfxMessageBox("监听成功"); Networking.SetAcceptFunc (AcceptCallback);//设置接受连接时的回调函数 } else AfxMessageBox("监听失败"); } void CBWChessDlg::OnUnlink() { if( Connection->IsConnected ()) Connection->Disconnect (); if(Sever==1)//为服务器 Networking.StopListen (); Sever=2;//设为断开状态 } int CBWChessDlg::Senddata(int x, int y, int command)//发送数据 { char sz[11]; sz[0]=(char)(command+48); sz[1]=(char)(x+48); sz[2]=(char)(y+48); sz[3]='B'; sz[4]='W'; sz[5]='C'; sz[6]='H'; sz[7]='E'; sz[8]='S'; sz[9]='S'; sz[10]='\0'; if(Connection->Send(sz, strlen (sz))==SOCKET_ERROR ) { AfxMessageBox("数据发送失败"); return 0; } return 1; } void CBWChessDlg::Newchess(int ptBest_x,int ptBest_y)//当对方数据到达时,更新窗口 { m_Mutex.Lock(); m_byColor = !m_byColor; // 1-Black 0-White,切换对手 duplicate();//保存副本 m_HintOnce=0; m_PeekOnce=0; BtoW(ptBest_y,ptBest_x,m_byColor+1);//将棋盘上被夹住的子变色 CPoint pt; pt.x = ptBest_x*m_wStoneWidth + m_wXNull+m_wStoneWidth/2; pt.y = ptBest_y*m_wStoneHeight + m_wYNull+m_wStoneWidth/2; m_CurPt.x=ptBest_x; m_CurPt.y=ptBest_y; ClientToScreen(&pt); MoveCursor(pt.x, pt.y);//移动光标,此时m_byColor代表的是当前棋手的颜色 AddStringToList(ptBest_y,ptBest_x,m_byColor);//将信息加入列表框 InvalidateRect(m_Client, FALSE); UpdateWindow();//更新棋盘 PlaySounds(IDSOUND_PUTSTONE); if(m_Skip!=1&&pppp!=100) Ring(IsEnd(!m_byColor+1));//作善后处理,包括“游戏结束或对手无子可走” else { int kk=IsEnd(!m_byColor+1); if(kk==0) m_Skip=1; else m_Skip=0; Calcu_BW(); ShowNumber(); if(pppp==100) { int win=0; int addp=0; m_bGameOver = TRUE; if(m_TimerOn) { KillTimer(PASSEDTIME); m_TimerOn=0; } CString str1,str2, str3,strPrompt; TCHAR str[128]; g_nStoneNum=abs(num_black-num_white); g_nBestMark=abs((num_white+num_black)*(num_white-num_black)); if(!(num_black && num_white)) g_nBestMark+=800; if(num_white>num_black)//白 胜 addp=1; if(num_white<num_black)//黑 胜 addp=2; if(num_white==num_black)//平局 { str1.LoadString(IDS_TIE_CHINESE); win=1; addp=3; } else if((g_bUserBlack && (num_white>num_black)) || ((!g_bUserBlack) && (num_white<num_black))) { if(!num_white || !num_black) str1.LoadString(IDS_COMPUTERWIN0_CHINESE); else if(g_nStoneNum>=40) str1.LoadString(IDS_COMPUTERWIN1_CHINESE); else str1.LoadString(IDS_COMPUTERWIN2_CHINESE); } else if((g_bUserBlack && (num_white<num_black)) || ((!g_bUserBlack) && (num_white>num_black))) { win=1; if(!num_white || !num_black) str1.LoadString(IDS_USERWIN0_CHINESE); else if(g_nStoneNum<=6) str1.LoadString(IDS_USERWIN2_CHINESE); else str1.LoadString(IDS_USERWIN1_CHINESE); } if(num_white!=num_black) { if(num_white && num_black) { wsprintf(str, str1.GetBuffer(256), g_nStoneNum); strPrompt=str; } else strPrompt=str1; } else strPrompt=str1; AddStringToList(0,0,0,addp); PlaySounds((win==0) ? IDSOUND_COMPUTERWIN : IDSOUND_USERWIN ); AfxMessageBox(strPrompt+" "+str2);//弹出胜负的对话框 BOOL bWinner = FALSE; if (g_nBestMark>g_nMark1) bWinner = TRUE;//打破了记录 if (bWinner&&(win==1))//存储记录 { if (g_nSkill == 1) { g_nTime1 = g_nStoneNum;//棋子的数目 g_nMark1=g_nBestMark;//所得的分数 } else if (g_nSkill == 2) { g_nTime2 = g_nStoneNum; g_nMark2=g_nBestMark; } if (g_nSkill == 3) { g_nTime3 = g_nStoneNum; g_nMark3=g_nBestMark; } } }//end if(pppp==100) if(m_Skip==1) { CString str3,str2; if((g_bUserBlack && !m_byColor) || (!g_bUserBlack && m_byColor)) str3.LoadString(IDS_USER_NOPLACE_CHINESE); else if((g_bUserBlack && m_byColor) || (!g_bUserBlack && !m_byColor)) str3.LoadString(IDS_COMPUTER_NOPLACE_CHINESE); str2.LoadString(IDS_TITLE_CHINESE); AfxMessageBox(str3+" "+str2); m_Skip=1; m_byColor=!m_byColor; }//end if(m_Skip==1) }//end else if(!m_bGameOver && g_bPeepOften) OnCanplace();//显示位置 if(m_Skip==1)//m_Skip==1表示我无子可走,由对手继续走 ready=false;//当前用户获得了使用权!!!!m_bGameOver && !m_Skip) else ready=true; if(m_bGameOver) ready=false; m_Mutex.Unlock(); } //抄写Ring 的代码 //本文件共2500行程序